library ieee;
use ieee.std_logic_1164.all;

-- This arbitrary state machine is probably not very useful in reality, but demonstrates 

entity test_bench_128 is
    port (clock               : in  std_logic;
          reset               : in  std_logic;
          q                   : out std_logic_vector(126 downto 0);
          en_0, en_1, en_2    : out std_logic;
          gen_0, gen_1, gen_2 : in  std_logic_vector(127 downto 0)
    );
end test_bench_128;

architecture behavior of test_bench_128 is

-- Define the state variable
type   state_type is (mem_state, mem_rec_a_state, mem_rec_b_state, mem_rec_c_state, gen_0_state_1, gen_0_state_2, gen_0_state, gen_1_state_1, gen_1_state_2, gen_1_state, gen_2_state_1, gen_2_state_2, gen_2_state);
signal my_state_reg, my_next_state                   : state_type := mem_state;
signal mem_data, mem_a ,mem_b, mem_c                 : std_logic_vector(127 downto 0);
signal mem_addr                                      : std_logic_vector(11 downto 0) := "000000000000";
signal mem_inc, en_ff                                : std_logic := '0';
signal gen_0_data, gen_1_data, gen_2_data            : std_logic_vector(127 downto 0);
signal data_sel                                      : std_logic_vector(1 downto 0);

component rom_1port_128 is
	port
	(
		address		: in  std_logic_vector (11 downto 0);
		clock		: in  std_logic  := '1';
		q		    : out std_logic_vector (127 downto 0)
	);
end component;

component addr_adder is
	port
	(
		aclr		: in  std_logic;
		clock		: in  std_logic;
		cnt_en		: in  std_logic;
		q		    : out std_logic_vector (11 downto 0)
	);
end component;

component data_ff_128 is
	port
	(
		aclr		: in  std_logic;
		clock		: in  std_logic;
		data		: in  std_logic_vector (127 downto 0);
		enable		: in  std_logic;
		q		    : out std_logic_vector (127 downto 0)
	);
end component;

component mux4to1_128 is
    port (d0,d1,d2,d3         : in  std_logic_vector(126 downto 0);
          q                   : out std_logic_vector(126 downto 0);
          sel                 : in  std_logic_vector(1 downto 0)
    );
end component;

begin

-- Update state on rising edges or a reset
process(clock,reset,my_next_state)
	begin
	    if (reset='1') then
            my_state_reg <= mem_state;
        elsif (clock'event and clock='1') then
			my_state_reg <= my_next_state;
		end if;
end process;

-- Next State Calculation
process(my_state_reg,mem_a(2 downto 0),gen_0_data(0),gen_1_data(0),gen_2_data(0)) 
	begin
		case my_state_reg is 
            when mem_state =>
                if (mem_a(0)='0') then
		            my_next_state <= mem_state;
		        else
		            if (mem_a(2 downto 1)="00") then
		                my_next_state <= gen_0_state_1;
		            elsif (mem_a(2 downto 1)="01") then
		                my_next_state <= gen_1_state_1;
		            elsif (mem_a(2 downto 1)="10") then
		                my_next_state <= gen_2_state_1;
		            else
		                my_next_state <= mem_state;
		            end if;
		        end if;
		    when mem_rec_a_state =>
		        my_next_state <= mem_rec_b_state;
		    when mem_rec_b_state =>
		        my_next_state <= mem_rec_c_state;
		    when mem_rec_c_state =>
		        my_next_state <= mem_state;
		    when gen_0_state_1 =>
		        my_next_state <= gen_0_state_2;
		    when gen_0_state_2 =>
		        my_next_state <= gen_0_state;
		    when gen_0_state =>
		        if (gen_0_data(0)='0') then
		            my_next_state <= gen_0_state;
		        else
		            my_next_state <= mem_rec_a_state;
		        end if;
		    when gen_1_state_1 =>
		        my_next_state <= gen_1_state_2;
		    when gen_1_state_2 =>
		        my_next_state <= gen_1_state;
		    when gen_1_state =>
		        if (gen_1_data(0)='0') then
		            my_next_state <= gen_1_state;
		        else
		            my_next_state <= mem_state;
		        end if;
		    when gen_2_state_1 =>
		        my_next_state <= gen_2_state_2;
		    when gen_2_state_2 =>
		        my_next_state <= gen_2_state;
		    when gen_2_state =>
		        if (gen_2_data(0)='0') then
		            my_next_state <= gen_2_state;
		        else
		            my_next_state <= mem_state;
		        end if;
		end case;
end process;

process(my_state_reg,mem_a(2 downto 0),mem_b,mem_c,gen_0(0),gen_1(0),gen_2(0))
    begin
        en_0 <= '0';
        en_1 <= '0';
        en_2 <= '0';
        en_ff <= '0';
        mem_data <= "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000";
        case my_state_reg is 
            when mem_state =>
                data_sel <= "00";
                mem_inc <= '1';
                en_ff <= '1';
                mem_data <= mem_b;
                en_0 <= mem_a(0) and (mem_a(1) nor mem_a(2));
                en_1 <= mem_a(0) and (mem_a(1) and not mem_a(2));
                en_2 <= mem_a(0) and (mem_a(1) and mem_a(2));
            when mem_rec_a_state =>
                data_sel <= "00";
                mem_inc <= '1';
                en_ff <= '1';
                mem_data <= mem_c;
            when mem_rec_b_state =>
                data_sel <= "00";
                mem_inc <= '1';
                en_ff <= '1';
                mem_data <= mem_c;
            when mem_rec_c_state =>
                data_sel <= "00";
                mem_inc <= '1';
                en_ff <= '1';
                mem_data <= mem_c;
            when gen_0_state_1 =>
                data_sel <= "01";
                mem_inc <= '0';
                en_0 <= '1';
                en_ff <= '1';
            when gen_0_state_2 =>
                data_sel <= "01";
                mem_inc <= '0';
                en_0 <= '1';
                en_ff <= '1';
            when gen_0_state =>
                data_sel <= "01";
                mem_inc <= gen_0(0);
                en_0 <= '1';
                en_ff <= '0';
            when gen_1_state_1 =>
                data_sel <= "10";
                mem_inc <= '0';
                en_1 <= '1';
                en_ff <= '1';
            when gen_1_state_2 =>
                data_sel <= "10";
                mem_inc <= '0';
                en_1 <= '1';
                en_ff <= '1';
            when gen_1_state =>
                data_sel <= "10";
                mem_inc <= gen_1(0);
                en_1 <= '1';
                en_ff <= '0';
            when gen_2_state_1 =>
                data_sel <= "11";
                mem_inc <= '0';
                en_2 <= '1';
                en_ff <= '1';
            when gen_2_state_2 =>
                data_sel <= "11";
                mem_inc <= '0';
                en_2 <= '1';
                en_ff <= '1';
            when gen_2_state =>
                data_sel <= "11";
                mem_inc <= gen_2(0);
                en_2 <= '1';
                en_ff <= gen_2(0);
        end case;
end process;

rom: rom_1port_128  port map(mem_addr, clock, mem_a);
add: addr_adder port map(reset, clock, mem_inc, mem_addr); 

ff1: data_ff_128 port map(reset,clock,mem_a,en_ff,mem_b);
ff2: data_ff_128 port map(reset,clock,mem_b,en_ff,mem_c);

mux: mux4to1_128 port map(mem_data(127 downto 1),gen_0_data(127 downto 1),gen_1_data(127 downto 1),gen_2(127 downto 1),q,data_sel);

ff3: data_ff_128 port map(reset,clock,gen_0,'1',gen_0_data);
ff4: data_ff_128 port map(reset,clock,gen_1,'1',gen_1_data);
ff5: data_ff_128 port map(reset,clock,gen_2,'1',gen_2_data);

end behavior;